﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qianke.Core.Common
{
    /// <summary>
    /// 编码生成器：加密/解密多个字段生成一个二维码或者条码
    /// 使用场景： 车站票号  会员编号
    /// 将多个字段要生成一个码  比如 车站：OrganId=10095  车站票号：123223 过期时间：20221114101111
    /// 生成的码如：N6S31XSGRNXWCAMQ
    /// 就可以作为一个加密的密文生成二维码了
    /// 生成的码自带合格性检测
    /// </summary>
    public class CodeGenerate
    {
        /// <summary>
        /// 不同版本编码顺序
        /// </summary>
        private List<string> _fieldArray = new List<string>();

        private string _perfix { set; get; }

        /// <summary>
        /// 初始化生成器 
        /// </summary>
        /// <param name="verFormat">不同版本编码顺序 如：OrganId|OrderId|OrderDetailId</param>
        /// <param name="prefix">前缀</param>
        /// <exception cref="ArgumentNullException"></exception>
        public CodeGenerate(string verFormat, string prefix = "")
        {
            if (verFormat == null || verFormat.Length == 0)
                throw new ArgumentNullException(nameof(verFormat));
            _fieldArray = verFormat.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries).ToList();
            _perfix = prefix;
        }


        private static string _base36Key = "QRM67FGSWX4T0BP1NOY9AUEH2IJK35L8VCDZ";
        /// <summary>
        /// 根据伪36进制字符串转换信息
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private long FromBase36(string str)
        {
            long v = 0;
            for (var i = 0; i < str.Length; i++)
            {
                v *= 36;
                for (var j = 0; j < _base36Key.Length; j++)
                {
                    if (_base36Key[j] == str[i])
                    {
                        v += j;
                        break;
                    }
                }
            }
            return v;
        }

        /// <summary>
        /// 转换为伪36进制数
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        private string ToBase36(long v)
        {
            byte tv = (byte)(v % 36);
            var uv = (long)(v / 36);
            if (uv == 0)
                return _base36Key[tv].ToString();
            return ToBase36(uv) + _base36Key[tv];
        }

        public string ToString(Dictionary<string, long> dict)
        {
            var strList = new List<string>();
            foreach (var field in _fieldArray)
            {
                if (dict.ContainsKey(field))
                {
                    var val = ToBase36(dict[field]);
                    strList.Add(ToBase36(val.Length) + val);
                }
                else
                    strList.Add(ToBase36(0));
            }
            var srcCode = string.Join("", strList);
            return _perfix + ToBase36((srcCode.Length + 1)) + srcCode;
        }

        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="code"></param>
        public Dictionary<string, long> LoadCode(string code)
        {
            try
            {
                if(!string.IsNullOrEmpty(_perfix))
                {
                    if(code.StartsWith(_perfix))
                        code= code.Substring(_perfix.Length);
                }

                //验证长度规则
                if (FromBase36(code.Substring(0, 1)) != code.Length)
                {
                    Trace.WriteLine("码长度不等");
                    return null;
                }
                var context = code.Substring(1);

                //核载
                var dict = new Dictionary<string, long>();
                foreach (var field in _fieldArray)
                {
                    var length = FromBase36(context.Substring(0, 1));
                    if (length + 1 > context.Length)
                        return null;

                    var val = context.Substring(1, (int)length);
                    dict[field] = FromBase36(val);
                    context = context.Substring((int)length + 1);
                }
                return dict;
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
                return null;
            }
        }

        /// <summary>
        /// 转换时间
        /// </summary>
        /// <param name="timeValue"></param>
        /// <returns></returns>
        public DateTime ToDateTime(long timeValue)
        {
            return DateTime.ParseExact(timeValue.ToString(), "yyyyMMddHHmmss", null);
        }


        /// <summary>
        /// 测试使用方法
        /// </summary>
        public void Test()
        {
            CodeGenerate codeGenerate = new CodeGenerate("OrganId|CreateTime|MemberCardNo");

            var dict = new Dictionary<string, long>()
            {
                ["OrganId"] = 10095,
                ["CreateTime"] = DateTime.Now.ToString("yyyyMMddHHmmss").ToInt64(0),
                ["MemberCardNo"] = 12232232
            };
            foreach (var node in dict)
            {
                Console.WriteLine($"{node.Key} = {node.Value}");
            }

            var code = codeGenerate.ToString(dict);
            Console.WriteLine(code);

            dict = codeGenerate.LoadCode(code);
            foreach (var node in dict)
            {
                Console.WriteLine($"{node.Key} = {node.Value}");
            }
        }
    }
}
